package com.video.demo.utils;


import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.time.DateUtils;

/**
 * 时间格式处理类
 *
 * @author CHENQUAN
 * @date 2016年9月13日
 */
public class DateUtil extends DateUtils {
    /**
     * 1分钟
     */
    private static final long ONE_MINUTE = 60000L;
    /**
     * 1小时
     */
    private static final long ONE_HOUR = 3600000L;
    /**
     * 1天
     */
    private static final long ONE_DAY = 86400000L;
    /**
     * 1周
     */
    private static final long ONE_WEEK = 604800000L;

    private static final String ONE_SECOND_AGO = "秒前";
    private static final String ONE_MINUTE_AGO = "分钟前";
    private static final String ONE_HOUR_AGO = "小时前";
    private static final String ONE_DAY_AGO = "天前";
    private static final String ONE_MONTH_AGO = "月前";
    private static final String ONE_YEAR_AGO = "年前";
    /**
     * yyyyMMdd
     */
    public static final String ISO_DATE_FORMAT = "yyyyMMdd";
    /**
     * yyyy-MM-dd
     */
    public static final String ISO_EXPANDED_DATE_FORMAT = "yyyy-MM-dd";
    /**
     * yyyy-MM-dd hh:mm:ss
     */
    public static String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    /**
     * yyyyMMddHHmmss
     */
    public static String DATE_PATTERN = "yyyyMMddHHmmss";
    /**
     * yyyyMMddHHmmssSSS 带毫秒的字符串
     */
    public static String DATE_MILLI_PATTERN = "yyyyMMddHHmmssSSS";

    /**
     * 时间转换
     *
     * @param date 需比对的时间
     * @return 秒前、分钟前、小时前、几天前、月前
     */
    public static String format(Date date) {
        if (null == date) {
            return null;
        }
        long delta = new Date().getTime() - date.getTime();
        if (delta < 1L * ONE_MINUTE) {
            long seconds = toSeconds(delta);
            return (seconds <= 0 ? 1 : seconds) + ONE_SECOND_AGO;
        }
        if (delta < 45L * ONE_MINUTE) {
            long minutes = toMinutes(delta);
            return (minutes <= 0 ? 1 : minutes) + ONE_MINUTE_AGO;
        }
        if (delta < 24L * ONE_HOUR) {
            long hours = toHours(delta);
            return (hours <= 0 ? 1 : hours) + ONE_HOUR_AGO;
        }
        if (delta < 48L * ONE_HOUR) {
            return "昨天";
        }
        if (delta < 73L * ONE_HOUR) {
            return "前天";
        }
        if (delta < 30L * ONE_DAY) {
            long days = toDays(delta);
            return (days <= 0 ? 1 : days) + ONE_DAY_AGO;
        }
        if (delta < 12L * 4L * ONE_WEEK) {
            long months = toMonths(delta);
            return (months <= 0 ? 1 : months) + ONE_MONTH_AGO;
        } else {
            long years = toYears(delta);
            return (years <= 0 ? 1 : years) + ONE_YEAR_AGO;
        }
    }

    /**
     * 秒
     *
     * @param date 获取秒
     * @return 秒
     * @author CHENQUAN
     * @date 2016年10月26日
     */
    private static long toSeconds(long date) {
        return date / 1000L;
    }

    private static long toMinutes(long date) {
        return toSeconds(date) / 60L;
    }

    private static long toHours(long date) {
        return toMinutes(date) / 60L;
    }

    private static long toDays(long date) {
        return toHours(date) / 24L;
    }

    private static long toMonths(long date) {
        return toDays(date) / 30L;
    }

    private static long toYears(long date) {
        return toMonths(date) / 365L;
    }


    /**
     * 时间转换为秒
     *
     * @param date 时间
     * @return 秒
     * @author CHENQUAN
     * @date 2017年9月20日
     */
    public static long toSeconds(Date date) {
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        String[] time = format.format(date).split(":");
        int hour = Integer.parseInt(time[0]);
        int min = Integer.parseInt(time[1]);
        int sec = Integer.parseInt(time[2]);
        return hour * 3600 + min * 60 + sec;
    }

    /**
     * 获取时间对应年份
     *
     * @param date 指定时间
     * @return 年份
     */
    public static int getYear(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.YEAR);
    }


    /**
     * 获取时间对应月份
     *
     * @param date 指定时间
     * @return 月份
     */
    public static int getMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.MONTH) + 1;
    }

    /**
     * 获取时间对应天
     *
     * @param date 指定时间
     * @return 天
     */
    public static int getDayOfYear(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.DAY_OF_YEAR);
    }

    /**
     * 获取当日0点时间
     *
     * @param date
     * @return 时间
     */
    public static Date getStartTime(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 获取当日23:59:59时间
     *
     * @param date
     * @return 时间格式
     */
    public static Date getEndTime(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        return cal.getTime();
    }

    /**
     * 格式化日期，返回符合格式的字符串
     *
     * @param date     时间
     * @param formater 如:yyyy-MM-dd HH:mm:ss
     * @return 格式化时间
     */
    private static String getDateStrCompact(Date date, String formater) {
        if (date == null) {
            return "";
        }
        SimpleDateFormat format = new SimpleDateFormat(formater);
        String str = format.format(date);
        return str;
    }

    /**
     * 格式 化日期，返回符合格式的字符串
     *
     * @param date
     * @param formatStr 默认 yyyy-MM-dd HH:mm:ss
     * @return 格式化时间
     */
    public static String dateToString(Date date, String formatStr) {
        if (formatStr == null || "".equals(formatStr.trim())) {
            formatStr = "yyyy-MM-dd HH:mm:ss";
        }
        return getDateStrCompact(date, formatStr);
    }

    /**
     * 格式 化日期，返回符合格式的字符串
     *
     * @param date
     * @return 格式化时间
     */
    public static String dateToString(Date date) {
        return dateToString(date, null);
    }

    /**
     * 格式化日期字符串，返回符合格式的date
     *
     * @param dateStr
     * @param formater 如:yyyy-MM-dd HH:mm:ss
     * @return 时间格式后时间
     * @throws ParseException 格式错误异常
     */
    public static Date stringToDate(String dateStr, String formater)
            throws ParseException {
        Date date = null;
        if (dateStr.length() == 8&&dateStr.indexOf(":")==2) {
            formater = "HH:mm:ss";
        }else if (dateStr.length() == 8) {
            formater = "yyyyMMdd";
        }else if (dateStr.length() == 10) {
            formater = "yyyy-MM-dd";
        }else if (formater == null || "".equals(formater.trim())) {
            formater = "yyyy-MM-dd HH:mm:ss";
        }
        SimpleDateFormat format = new SimpleDateFormat(formater);
        if (!StringUtil.isNotBlank(dateStr)) {
            return date;
        } else if (dateStr.indexOf("/") > 0) {
            dateStr = dateStr.replace("/", "-");
        }
        date = format.parse(dateStr);
        return date;
    }

    /**
     * 格式化日期字符串，返回符合格式的date
     *
     * @param dateStr
     * @return 时间格式后时间
     * @throws ParseException 格式错误异常
     */
    public static Date stringToDate(String dateStr)
            throws ParseException {
        return stringToDate(dateStr, null);
    }

    /**
     * 在系统当前时间的基础上增减N天
     *
     * @param days 增减的天数 (为正数则增加，为负数则减少)
     * @return Date
     * @author CHENQUAN
     * @date 2016年9月29日
     */
    public static Date addDays(int days) {
        return addDays(new Date(), days);
    }

    /**
     * 取某一日期增减 n 值后的日期, n 由 dateField 决定是年、月、日 根据增加or减少的时间得到新的日期
     *
     * @param date      参照日期
     * @param counts    增减的数值
     * @param dateField int 需操作的日期字段, 取值范围如下 Calendar.YEAR 年 Calendar.MONTH 月
     *                  Calendar.DATE 日 .... Calendar.SECOND 秒
     * @return Date
     */
    public static Date add(Date date, int counts, int dateField) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(dateField, counts);
        return calendar.getTime();
    }

    public static long getTimeInMillis(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.getTimeInMillis();
    }

    public static Date getDateFromMillis(long timeInMillis) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timeInMillis);
        return calendar.getTime();
    }

    /**
     * 获取当前日期所在周的第一天
     *
     * @param date 日期
     * @return 本周第一天日期
     * @author CHENQUAN
     * @date 2016年9月29日
     */
    public static Date getWeekStart(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        if (dayOfWeek > Calendar.MONDAY) { // 该date大于周一
            return getStartTime(addDays(date, Calendar.MONDAY - dayOfWeek));
        }
        if (dayOfWeek < Calendar.MONDAY) { // 该date是周日
            return getStartTime(addDays(date, -6));
        }
        return getStartTime(date);
    }

    /**
     * 获取当前日期所在周的最后一天
     */
    public static Date getWeekEnd(Date date) {
        return getEndTime(addDays(getWeekStart(date), 6));
    }

    /**
     * 获取当前日期所在月份的第一天
     */
    public static Date getMonthStart(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
        if (dayOfMonth > 1) {
            date = addDays(date, 1 - dayOfMonth);
        }
        return getStartTime(date);
    }

    /**
     * 获取当前日期所在月份的最后一天
     */
    public static Date getMonthEnd(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) + 1);
        return addDays(getEndTime(calendar.getTime()), -1);
    }

    /**
     * 根据年、月获取指定月份的起止日期
     *
     * @param year  年
     * @param month 月
     * @return 指定月份的起止日期
     */
    public static Date[] getMonthStartEndDate(int year, int month) {
        Date[] dates = new Date[2];
        Calendar start = Calendar.getInstance();
        start.set(Calendar.YEAR, year);
        start.set(Calendar.MONTH, month - 1);
        start.set(Calendar.DATE, 1);
        dates[0] = getMonthStart(start.getTime());
        dates[1] = getMonthEnd(start.getTime());
        return dates;
    }

    /**
     * 比较时间
     *
     * @param s1 时间1
     * @param s2 时间2
     * @return s1等于s2返回值等于0；s1时间在s2之前返回值小于0；s1时间在s2之后返回值大于0
     */
    public static Integer comparisonTime(String s1, String s2) throws ParseException {
        return comparisonTime(stringToDate(s1), stringToDate(s2));
    }

    /**
     * 比较时间
     *
     * @param date1 时间1
     * @param date2 时间2
     * @return s1等于s2返回值等于0；s1时间在s2之前返回值小于0；s1时间在s2之后返回值大于0
     */
    public static Integer comparisonTime(Date date1, Date date2) {
        java.util.Calendar c1 = java.util.Calendar.getInstance();
        java.util.Calendar c2 = java.util.Calendar.getInstance();
        c1.setTime(date1);
        c2.setTime(date2);
        return c1.compareTo(c2);
    }

    /**
     * 两个时间间的时间戳计算函数
     *
     * @param beginDate 开始时间
     * @param endDate   结束时间
     * @param field     Calendar 时间差的形式13:秒,12:分种,10:小时,5:天，4:周
     * @return 整数
     * @author CHENQUAN
     * @date 2016年12月14日
     */
    public static Long getDifference(Date beginDate, Date endDate, int field) {
        long result = 0;
        if (beginDate == null || endDate == null) {
            return 0L;
        }
        try {
            // 日期相减获取日期差X(单位:毫秒)
            long millisecond = endDate.getTime() - beginDate.getTime();
            /**
             * Math.abs((int)(millisecond/1000)); 绝对值 1秒 = 1000毫秒
             * millisecond/1000 --> 秒 millisecond/1000*60 - > 分钟
             * millisecond/(1000*60*60) -- > 小时 millisecond/(1000*60*60*24) -->
             * 天
             * */
            switch (field) {
                case Calendar.SECOND: // second
                    return (millisecond / 1000);
                case Calendar.MINUTE: // minute
                    return (millisecond / (1000 * 60));
                case Calendar.HOUR: // hour
                    return (millisecond / (1000 * 60 * 60));
                case Calendar.DATE: // day
                    return (millisecond / (1000 * 60 * 60 * 24));
                case Calendar.WEEK_OF_MONTH: // week
                    return (millisecond / (1000 * 60 * 60 * 24 * 7));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 返回固定格式的当前时间yyyy-MM-dd hh:mm:ss
     *
     * @return
     * @author CHENQUAN
     * @date 2016年9月13日
     */
    public static String dateToStringWithTime() {
        return dateToString(new java.util.Date(), DATETIME_PATTERN);
    }

    /**
     * 秒数转分秒00:00:00 格式
     *
     * @param time 秒数
     * @return 转为 00:00:00 格式
     * @author CHENQUAN
     * @date 2016年12月12日
     */
    public static String toMinuteSecond(long time) {
        String timeStr = null;
        long hour = 0;
        long minute = 0;
        long second = 0;
        if (time <= 0)
            return "00:00";
        else {
            minute = time / 60;
            if (minute < 60) {
                second = time % 60;
                timeStr = unitFormat(minute) + ":" + unitFormat(second);
            } else {
                hour = minute / 60;
                if (hour > 99)
                    return "99:59:59";
                minute = minute % 60;
                second = time - hour * 3600 - minute * 60;
                timeStr = unitFormat(hour) + ":" + unitFormat(minute) + ":"
                        + unitFormat(second);
            }
        }
        return timeStr;
    }

    /**
     * 秒数转分秒00:00:00 格式
     *
     * @param time 秒数
     * @return 转为 00:00:00 格式
     * @author CHENQUAN
     * @date 2016年12月12日
     */
    public static String toMinuteSecond(int time) {
        return toMinuteSecond((long) time);
    }

    /**
     * 秒数转分秒“1小时1分1秒” 格式
     *
     * @param time 秒数
     * @return 转为 “1小时1分1秒”格式
     * @author CHENQUAN
     * @date 2016年12月12日
     */
    public static String toChineseMinuteSecond(int time) {
        String timeStr = null;
        int hour = 0;
        int minute = 0;
        int second = 0;
        if (time <= 0)
            return "-";
        else {
            minute = time / 60;
            if (minute < 60) {
                second = time % 60;
                timeStr = (minute == 0 ? "" : minute + "分")
                        + (second == 0 ? "" : second + "秒");
            } else {
                hour = minute / 60;
                if (hour > 99)
                    return "99小时";
                minute = minute % 60;
                second = time - hour * 3600 - minute * 60;
                timeStr = hour
                        + "小时"
                        + (minute == 0 ? "" : minute + "分"
                        + (second == 0 ? "" : second + "秒"));
            }
        }
        return timeStr;
    }

    public static String unitFormat(int i) {
        String retStr = null;
        if (i >= 0 && i < 10)
            retStr = "0" + Integer.toString(i);
        else
            retStr = "" + i;
        return retStr;
    }

    public static String unitFormat(long l) {
        String retStr = null;
        if (l >= 0 && l < 10)
            retStr = "0" + Long.toString(l);
        else
            retStr = "" + l;
        return retStr;
    }

    /**
     * 获取起止时间内容每天起止时间列表
     *
     * @param startDate 起始时间
     * @param endDate   截至时间
     * @return Map<Date, Date> map.key为天开始时间，map.value为天的截至时间
     */
    public static Map<Date, Date> getDaysDate(Date startDate, Date endDate) {
        Map<Date, Date> map = new HashMap<>();
        // 计算日期之间相差周数
        long days = DateUtil.getDifference(startDate, endDate, 5) + 1l;
        for (int i = 0; i < days; i++) {
            Date nowDate = DateUtil.addDays(startDate, i);
            map.put(DateUtil.getStartTime(nowDate),
                    DateUtil.getEndTime(nowDate));
        }
        return map;
    }

    /**
     * 获取起止时间内容每周起止时间列表
     *
     * @param startDate 起始时间
     * @param endDate   截至时间
     * @return Map<Date, Date> map.key为周开始时间，map.value为周的截至时间
     */
    public static Map<Date, Date> getWeeksDate(Date startDate, Date endDate) {
        Map<Date, Date> map = new HashMap<>();
        // 计算日期之间相差周数
        long weeks = DateUtil.getDifference(startDate, endDate, 4) + 1l;
        for (int i = 0; i < weeks; i++) {
            Date nowDate = DateUtil.addDays(startDate, i * 7);
            map.put(DateUtil.getWeekStart(nowDate),
                    DateUtil.getWeekEnd(nowDate));
        }
        return map;
    }

    /**
     * 时间转Double类型
     *
     * @param date "HH:mm:ss"格式时间格式
     * @return Double类型
     */
    public static Double timeToDouble(Date date) {
        String time = DateUtil.dateToString(date, "HH:mm:ss");
        String[] split = time.split(":");
        Double ret = Integer.parseInt(split[0]) + Integer.parseInt(split[1])
                / 60.0 + Integer.parseInt(split[2]) / 60.0 / 60.0;
        return ret;
    }

    /**
     * 获取指定时间区间内的日期列表
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return
     */
    public static List<Date> getScheduleDays(Date startDate, Date endDate) {
        List<Date> list = new ArrayList<>();
        list.add(startDate);
        Calendar calBegin = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calBegin.setTime(startDate);
        Calendar calEnd = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calEnd.setTime(endDate);
        // 测试此日期是否在指定日期之后
        while (endDate.after(calBegin.getTime())) {
            // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
            calBegin.add(Calendar.DAY_OF_MONTH, 1);
            list.add(calBegin.getTime());
        }
        return list;
    }


    public static void main(String[] args) throws ParseException {
    	System.out.println(DateUtil.toMinuteSecond(1));
        System.out.println(DateUtil.addDays(-281).toLocaleString());
        System.out.println(getScheduleDays(DateUtil.addDays(-10), new Date()));
        System.out.println(DateUtil.addDays(new Date(), -1).toLocaleString());
        // s1等于s2返回值等于0；s1时间在s2之前返回值小于0；s1时间在s2之后返回值大于0
        System.out.println("comparisonTime=" + comparisonTime("2017-09-18 10:39:38", "2017-09-18 10:39:39"));
        System.out.println(DateUtil.getDifference(DateUtil.addHours(new Date(), -10), new Date(), Calendar.HOUR));
    }
}